/*--------------------------------------------------------------------------
 DEPUI-GFX-TK 3.0 - GPL portable source code libraries 
 http://www.deleveld.dds.nl/depui.htm
 See file docs/copying for copyright details
 ---------------------------------------------------------------------------*/
  /* Fix key recognition for MGRX and allegro

     Fix text title for lists and scroll objects

     Can you give a modal window the focus when it is popped up? Or maybe it
     shouldnt happen to avoid missed/redirected keyboard input.

     Fix offset of text chunks for different alignment and themes.

     Change theme drawing for focus? Or change focus handling

     Add background image to gfxsel dialog.  What extensions per platform a 
     define for this?

     Can you make a more sensible define so that DEGFX does nto include the
     standard pointer code?  MX_DEGFX_POINTER

     Make code conventions rules like MXDEBUG_ , uppercase and lower case,
     prefixes...

     Should tect chunks be MX_RECTATOM or maybe derived from MX_OBJ?

     Can I make sub-theme with basic drawing stuff (clip, hline, vline, text)
     so that a generic theme can be used?

     Text chunking can be used to inject control characters into interface
     strings.  A button chunker could recognise the & symbol and underline the
     following character.  Perhaps just using HTML is better...

     Make theme dialog and split theme selector from gfx mode selector.

     Think about a client/server approach. - Change tree traversal for drawing.
     - Make border a separate window. (probably not necessary) - Client gets
     pointer to big window the same size as the platform. The client cant use
     the root window because the client might want to open more than one window.

     Add version counter for make release.

     Make speed regression test.

     Make function/macro/define naming rules. - Macros that eval arguments more
     than once must be capila letters. other macros can be lower case.

     How can I make clever visual transformations for window drawing

     Make it possible for a window to be double buffered.

     Can I separate the gui-tree from the objects? This could make the system
     more safe because users could not traverse the tree which could be in
     protected memory space.

     Making objects at 0,0 makes conversion to a text mode/theme easier.

     Transparent windows works ok, but how should trans work wrt layering?

     Should lists be appended to or should create function be used for this?

     Marking window dirty when making new window means border remains not
     updated. - use mx_win_dirty

     Can I use debug flags to make sure that classes dont get called inside
     handlers?

     Make window unresizable.

     Make video noise window to check frame rates

     Should a font be constant or not? Const is good for compile time error
     checking, but works bad with atom destroying.  The mx_delete macro needs
     non-const pointers.  Should it?

     Make crashes impossible even from malformed events.  The biggest danger
     comes from incorrect data but I dont know how to fix this.

     Dont try to delete in list iteration.  You might need to remove from tree
     and delete.

     Events break the atomicity of operations.  So operations should preferrably
     be atomic i.e. generate no events.  This makes sure that objects dont get
     deleted while they are bieng iterated through.
*/

#define MXMODULE_THEME_ALL
#define MXMODULE_FONT_ALL
#define MXMODULE_DRIVER_ALL

#define MXMODULE_FILESEL
#define MXMODULE_FONTSEL
#define MXMODULE_GFXSEL
#define MXMODULE_THEMESEL
#define MXMODULE_EDITTEXT
#define MXMODULE_TEXTEDITOR
#define MXMODULE_ALERT
#define MXMODULE_SYSMENU

#include "depui/depui.c"

typedef struct APP {
        union {
                MX_WIN_DATA win;
                MX_TEXTUAL_DATA textual;
                MX_OBJ_DATA obj;
                MX_RECTATOM_DATA rectatom;
                MX_ATOM atom;
        } base;
} APP;

#define FONTSEL_ID 11
#define GFXMODE_ID 12
#define THEME_ID 13
#define ALERT_ID 14

void specialwin_class(void)
{
#ifdef MX_PLATFORM_DEGFX
	MX_WIN *w = (MX_WIN *) mx.obj;

    if (mx_eventmatch(MX_EXPOSE, w)) {
        if (mx_exposing()) {
            char ratetext[100];
            MX_RECT r = *mx_expose_rect();
    		const MX_RECT *rect = MXRECT(w);
            
            while (r.y1 <= r.y2) {
                MX_BITMAP_ITER ptr = mx_iter(r.x1, r.y1);
                const MX_BITMAP_ITER end = mx_iter(r.x2, r.y1) + 1;
                while (ptr != end)
                    *ptr++ = rand();
                ++r.y1;
            }
            sprintf(ratetext, "FPS: %i ", mx__.framerate);
        	mx_font_draw(0, ratetext, -1, rect->x1, rect->y1, MXRGB(255,255,255));
            mx_dirty(w, false);
        }

    } else
#endif
        mx_win_class();
}

void listwinhandler(MX_WIN * win)
{
#ifdef MX_PLATFORM_DEGFX
    if (mx_eventmatch(MX_EXPOSE, win)) {
        if (mx_exposing()) {
            MX_RECT r = *mx_expose_rect();
            
            while (r.y1 <= r.y2) {
                MX_BITMAP_ITER ptr = mx_iter(r.x1, r.y1);
                const MX_BITMAP_ITER end = mx_iter(r.x2, r.y1);
                while (ptr != end)
                    *ptr++ = rand();
                ++r.y1;
            }
        }
        
    } else {
        mx_win_handler(win);
        return;
    }
#endif
    
    mx_win_handler(win);
}

void handler(MX_WIN * win)
{
        if ((mx.event == MX_SELECT) && (mx.data)) {
                MX_WIN_DATA *newwin = 0;

                if (MXID(mx.obj) == THEME_ID) {
/*                        MX_TEXTEDITOR *f = mx_texteditor(0); */
                        MX_THEMESEL * f = mx_themesel(0);

                        MXDEBUG_ATOMNAME(f, "texteditor_win");
                        newwin = MXWIN(f);
                
#ifdef MXDEBUG
            int i = 0;
            const void * mem = mx__alloc_walk(0);
            
            fprintf(stderr, "#memory start\n");
            while (mem) {
                fprintf(stderr, "#%i %li %s:%li\n", i, mx__alloc_size, mx__alloc_file, mx__alloc_line);
                mem = mx__alloc_walk(mem);
                ++i;
            }
            fprintf(stderr, "#memory end\n");
#endif
        
                } else if (MXID(mx.obj) == FONTSEL_ID) {
                        MX_FONTSEL *f = mx_fontselwin(0, 0, 0, 0);

                        MXDEBUG_ATOMNAME(f, "fontsel_win");
                        mx_text_set(f, "Font select", -1, 0);
                        mx_fontsel_refresh(f);
                        newwin = MXWIN(f);

                } else if (MXID(mx.obj) == GFXMODE_ID) {
                        MX_GFXSEL *m = mx_gfxselwin(0, 0, 0, 0);

                        MXDEBUG_ATOMNAME(m, "gfxsel_win");
                        mx_modal(m);
                        mx_text_set(m, "Choose GFX mode", -1, 0);
                        newwin = MXWIN(m);
                }

                if (newwin) {
                        mx_defaultrect(newwin, 0);
                        mx__layout(MXOBJ(newwin), MX_LAYOUT_CENTER, 0, 0, 0);
                        mx_geometry(newwin);

                        mx_dirty(newwin, true);
                        mx_dirty(newwin->border, true);
                        return;
                }
        }

        mx_win_handler(win);
}

int main(int argc, char *argv[])
{
        APP *app;
        MX_WIN *w;
        MX_TEXTUAL *text;
        MX_BUTTON *btn, *btn1, *btn2;
        MX_LIST *list;
        MX_SCROLL *scroll;
        MX_EDITTEXT *edit;
        MX_ALERT* alert;

        (void) argc;
        (void) argv;

        if (!mx_start())
                return EXIT_FAILURE;

        mx_sysmenu();

        w = mx_win((MX_WIN *)0, 0, listwinhandler, 0);
        MXOBJ(w)->_class = specialwin_class;
        
/*      w = mx_win(0, 0, 0, 0); */
        mx_position(w, 150, 150, 200, 250);
        mx_dirty(w, true);
        MXDEBUG_ATOMNAME(w, "list_win");
        mx_text_set(w, "Listg Window", -1, 0);
        mx_geometry(w);

        list = mx_list((MX_LIST *)0, 0, w, 0);
        mx_position(list, 5, 5, 100, 100);
/**fix        mx_text_set(list, "A list", -1, 0); */
/**fix        mx_text_align(list, MX_ALIGN_RIGHT); */

        edit = mx_edittext((MX_EDITTEXT*)0, 0, w, 0);
        mx_text_set(edit, "This should be editable", -1, 0);
        mx_layout(edit, MX_LAYOUT_BOTTOM | MX_LAYOUT_X1, list, 0, 5);
        mx_defaultrect(edit, 0);

        mx_list_append(list, "Selgect 1 is very wide", -1, 0, 0);
        mx_list_append(list, "SelTect 2", -1, 0, 0);
        mx_list_append(list, "SelgTt 3", -1, 0, 0);
        mx_list_append(list, "SelgTt 4\n   has more\n   than one line", -1, 0, 0);
        mx_list_append(list, "SelgTt 5", -1, 0, 1);
        mx_list_append(list, "SelgTt 6", -1, 0, 0);
        mx_list_append(list, "SelgTt 7", -1, 0, 1);
        mx_list_append(list, "SelgTt 8", -1, 0, 0);
        mx_list_append(list, "SelgTt 9", -1, 0, 1);
        mx_list_append(list, "SelgTt 10", -1, 0, 0);
        mx_list_append(list, "SelgTt 11", -1, 0, 1);
        mx_list_append(list, "SelgTt 12", -1, 0, 2);
        mx_list_append(list, "SelgTt 13", -1, 0, 0);
        mx_list_append(list, "SelgTt 14", -1, 0, 0);
        mx_list_select_id(list, 2, true);
        mx_geometry(list);

        app = (APP *) mx_win((MX_WIN *)0, 0, handler, 0);
        mx_position(app, 50, 50, 250, 250);
        mx_dirty(app, true);
        MXDEBUG_ATOMNAME(app, "button_app");
        mx_text_set(app, "Buttong Window\nis what I am", -1, 0);
        mx_geometry(app);

        text = mx_textual((MX_TEXTUAL*) 0, 0, app, 0);
        mx_text_set(text, "Whatg am I\nDoing right\nNow?\n", -1, 0);
        mx_move(text, 10, 1);
        mx_defaultrect(text, 0);
        mx_geometry(text);

        btn = mx_button((MX_BUTTON *)0, 0, app, THEME_ID);
        mx_text_set(btn, "Theme select", -1, 0);
        mx_defaultrect(btn, 0);
        mx_layout(btn, (MX_LAYOUT_X1 | MX_LAYOUT_BOTTOM), text, 0, 2);
        mx_geometry(btn);

        btn1 = mx_button((MX_BUTTON *)0, 0, app, FONTSEL_ID);
        mx_text_set(btn1, "Font select (child)", -1, 0);
        mx_defaultrect(btn1, 0);
        mx_text_align(btn1, MX_ALIGN_VCENTER | MX_ALIGN_RIGHT);
        mx_layout(btn1, (MX_LAYOUT_X1 | MX_LAYOUT_BOTTOM), btn, 0, 2);
        mx_geometry(btn1);

        btn2 = mx_button((MX_BUTTON *)0, 0, app, GFXMODE_ID);
        mx_text_set(btn2, "Gfx select (modal)", -1, 0);
        mx_text_align(btn2, MX_ALIGN_VCENTER | MX_ALIGN_LEFT);
        mx_defaultrect(btn2, 0);
        mx_layout(btn2, (MX_LAYOUT_X1 | MX_LAYOUT_BOTTOM), btn1, 0, 2);
        mx_geometry(btn2);

        scroll = mx_scroll((MX_SCROLL *)0, 0, app, 1);
        mx_resize(scroll, 100, 100);
        mx_layout(scroll, (MX_LAYOUT_X1 | MX_LAYOUT_BOTTOM), btn2, 0,
                          2);

        btn = mx_button((MX_BUTTON *)0, 0, scroll, 0);
        mx_text_set(btn, "This is disabled", -1, 0);
        mx_defaultrect(btn, 0);
        mx_disable(btn, true);
        mx_move(btn, -10, -10);
        mx_geometry(btn);

        btn = mx_button((MX_BUTTON *)0, 0, scroll, 0);
        mx_text_set(btn, "another button", -1, 0);
        mx_defaultrect(btn, 0);
        mx_position(btn, 70, 150, MXDEFAULT, MXDEFAULT);
        mx_geometry(btn);

        mx_geometry(scroll);

        alert = mx_alert(ALERT_ID);
        mx_text_set(alert, "", -1, 0);
        mx_text_set(&alert->text, "unmovable\nunresizeable\nuncloseable\nnotitle\nwindow", -1, 0);
        mx_defaultrect(alert, 0);
        mx_win_noresize(alert, true);
/*        mx_win_noclose(alert, true);
        mx_win_notitle(alert, true); */
        mx_win_nomove(alert, true);
        mx_layout(alert, MX_LAYOUT_CENTER, (MX_OBJ*)0, 0, 0);
        mx_geometry(alert);

/*    fprintf(stderr, "MX_ATOM     = %i bytes\n", sizeof(MX_ATOM));
    fprintf(stderr, "MX_RECTATOM = %i bytes\n", sizeof(MX_RECTATOM));
    fprintf(stderr, "MX_OBJ      = %i bytes\n", sizeof(MX_OBJ));
    fprintf(stderr, "MX_BUTTON   = %i bytes\n", sizeof(MX_BUTTON));
    fprintf(stderr, "MX_WIN      = %i bytes\n", sizeof(MX_WIN));
*/

        return mx_execute();
}
